<?php
    if (!defined('__IS_LEAF__')) exit('Access Denied!');
    
    /**
     * 控制器、服务层、Dao层基类
     */
    class Base {

        /**
         * 魔术方法，获取调用的属性，并解析，如果是Dao或Service，则实例化，其他情况调用Dao层的_daoGet
         */
        public function __get($call){
            //判断是否为userDao类型的属性，如果是，则进行dao实例化
            if( $this->_isDao($call) ){
                return $this->_instanceDao($call);
            }elseif( $this->_isService($call) ){
            //判断是否为服务层service，如果是，则实例化service层
                return $this->_instanceService($call);
            }else{
            //如果既不是要实例化dao也不是要实例化service，那么调用dao中的__get魔术方法
            }
        }

        /**
         * 判断被调用的属性其是否符合DAO调用，符合的类型如：userDao
         * @access private
         * @param string $call 被调用的属性
         */ 
        final protected function _isDao($call){
            $return = false;
            if(strlen($call)>3){
                //截取后三个字符，与Dao字符串比较
                $cmp = strcmp( substr($call, -3, 3), 'Dao');
                if($cmp===0){
                    $return = true;
                }
            }
            return $return;
        }


        /**
         * 将通过检查的字符串实例化为Dao对象
         * @access protected
         * @param string $call 要实例化为Dao的字符串
         */
        final protected function _instanceDao($call){
            static $daoInstances = array();
            //根据$call属性，获取表名
            if(isset($daoInstances[$call])) return $daoInstances[$call];
            $tableName = $this->_getTableName($call);
            return $instanceDao = new Dao($tableName);
        }

        /**
         * 获取Dao属性对应的表名
         */
        final protected function _getTableName($daoStr){
            $daoStr = lcfirst($daoStr);
            //判断参数类型的合法性
            if(!is_string($daoStr)) $this->error(L('param').'$daoStr'.L('must_string'));
            //将userNotifyDao这种形式，转换为 prefix_user_notify或prefix_usernotify等形式的表模型
            $callArr = explode('Dao', $daoStr);
            $callArr = array_filter($callArr);
            $tableStr = $callArr[0];
            //获取真实表名，如果为userNotify这种中间有大写的形式，则转为user_notify的形式
            //先用大写分割，然后转为小写，最后重新拼接
            $tempArr = preg_split( "/(?=[A-Z])/", $tableStr);
            foreach ($tempArr as $key => &$value) {
                $value = strtolower($value);
            }
            $tableName = C('db_prefix').implode('_', $tempArr);
            return $tableName;
        }

        /**
         * 判断是否为Service调用，符合类型如：userService，必须为Service结尾
         * @access protected
         * @param string $call 要实例化为Service的字符串
         */
        final protected function _isService($call){
            $return = false;
            if(strlen($call)>3){
                //截取后三个字符，与Dao字符串比较
                $cmp = strcmp( substr($call, -7, 7), 'Service');
                if($cmp===0){
                    $return = true;
                }
            }
            return $return;
        }

        /**
         * 实例化服务层（也叫业务层）
         * @access protected
         * @param string $call 要实例化为Service的字符串
         */
        final protected function _instanceService($call){
            //判断参数类型的合法性
            if(!is_string($call)) $this->error(L('param').'$call'.L('must_string'));
            static $serviceInstances = array();
            //根据$call属性，获取表名
            if(isset($serviceInstances[$call])) return $serviceInstances[$call];
            $serviceInstances[$call] = new $call;
            return $serviceInstances[$call];
        }

        /**
         * 获取经过过滤的post数组或post数组中的元素，默认去除html标签
         * @access protected
         * @param mixed $input 获取安全的post数据的输入值
         */
        final protected function _post($input, $filter=false){

        }

        /**
         * 同方法_post
         * @access protected
         * @param mixed $input 获取安全的post数据的输入值
         */
        final protected function _get($input, $filter=false){
        }

        /**
         * 通用的错误处理方法
         * @access protected
         * @param string $msg 要输错的错误信息
         * @param int $type 要输错的错误类型
         */
        final protected function error($msg ,$type){
            error($msg, $type);
        }


        /**
         * 通用加载方法
         * @access protected
         * @param string $class 要加载的文件
         * @param string $type 加载的文件类型
         */
        final protected function load($class, $type){

        }


    }
